<?php
/**
 * Created by PhpStorm.
 * User: yiyu
 * Email: smalleasyu@gmail.com
 * Date: 2020-01-18 20:34:47
 * Desc: 小程序注册新用户
 */

namespace app\api\controller\wx;

use app\api\controller\ApiBaseController;
use app\base\model\user\{User, UserWx, UserFriend, UserStatisticsInfo};
use app\core\util\{JwtUtil, TokenUtil};
use app\api\service\UserRegisterService;
use app\base\service\WeChat\{WeChatBaseService, MiniProgramQrCodeService};
use app\api\service\MiniProgram\MiniProgramBaseService;
use app\core\exception\{BusinessException, ErrorCode};
use app\core\log\Log4dd;
use think\Db;
use think\Request;

class MiniProgramController extends ApiBaseController
{

    protected $beforeActionList = [
        'checkLogin' => ['only' => 'userinfo'],//只有userInfo方法要检查是否有user_id
    ];

    public function login()
    {
        Log4dd::info('小程序login 请求原始数据', ['request_params' => Request::instance()->param(false)]);

        $app_id = input('app_id/s', '');

        if (empty($app_id)) {
            throw new BusinessException(ErrorCode::MINI_PROGRAM_LACK_PARAMS, 'app_id不能为空');
        }

        $code = input('code/s', '');

        if (empty($code)) {
            throw new BusinessException(ErrorCode::MINI_PROGRAM_LACK_PARAMS, 'code不能为空');
        }

        Db::startTrans();

        try {

            $config = WeChatBaseService::instance()->getConfigByAppId($app_id);

            $new_config = [
                'app_id' => $config['app_id'],
                'secret' => $config['secret'],
            ];

            $wx_info = MiniProgramBaseService::instance()->getMiniProgramOpenIds($new_config, $code);

            Log4dd::info('小程序login code换取的数据', $wx_info);

            if (!isset($wx_info['openId']) || empty($wx_info['openId'])) {
                throw new BusinessException(ErrorCode::COMMON_ERROR, '获取openId失败,请稍后再试');
            }

            $user_id = 0;

            $need_create_user = false;

            $wx_id = 0;

            if (false == $need_create_user) {
                $user_bind_info = UserWx::getWxInfoByMiniProgramOpenId($config['app_id'], $wx_info['openId']);
                if ($user_bind_info) {
                    $wx_id = $user_bind_info['wx_id'];
                    if (empty($user_bind_info['user_id'])) {
                        $need_create_user = true;
                    } else {
                        $user_id = $user_bind_info['user_id'];
                    }
                } else {
                    $need_create_user = true;
                }
            }


            if (false == $need_create_user) {
                if (isset($wx_info['unionId']) && !empty($wx_info['unionId'])) {
                    $user_bind_info = UserWx::getUserIdByUnionId($config['app_id'], $wx_info['unionId']);
                    if ($user_bind_info) {
                        $wx_id = $user_bind_info['wx_id'];
                        if (empty($user_bind_info['user_id'])) {
                            $need_create_user = true;
                        } else {
                            $user_id = $user_bind_info['user_id'];
                        }
                    } else {
                        $need_create_user = true;
                    }
                }
            }


            $refer_code = input('refer_code/s', '');

            $new_user_info['refer_code'] = $refer_code;


            Log4dd::info('小程序login 判断是否注册', [$user_id, $wx_id, $need_create_user]);

            if ($need_create_user) {
                $user_id = UserRegisterService::instance()->miniProgramUserRegister($new_config, $new_user_info);
            }

            Log4dd::info('小程序login 获取user_id', [$user_id, $wx_id, $need_create_user]);


            if (false == $user_id || empty($user_id)) {
                Db::rollback();
                return $this->errorReturn(ErrorCode::COMMON_ERROR, '注册用户失败');
            }

            $wx_data = [
                'app_id' => $app_id,
                'open_id' => $wx_info['openId'],
                'union_id' => $wx_info['unionId'] ?? '',
                'user_id' => $user_id,
                'open_id_type' => UserWx::MINI_PROGRAM_OPEN_ID_TYPE
            ];

            if ($wx_id) {
                UserWx::updateWxInfo(['wx_id' => $wx_id], $wx_data);
            } else {
                UserWx::insertWxInfo($wx_data);
            }

            //绑定好友关系
            if ($need_create_user && $refer_code) {
                UserFriend::bindFriendByReferCode($user_id, $refer_code, UserFriend::SOURCE_MINI_INVITE);
            }

            $token = JwtUtil::getToken(['user_id' => $user_id]);

            //设置一个token副本，用于校验注销
            TokenUtil::setApiLoginTokenCopy($user_id, $token);

            Db::commit();
            return $this->successReturn(['AUTHORIZATION' => $token]);
        } catch (BusinessException $e) {
            Db::rollback();
            Log4dd::info("小程序初始化注册用户失败:{$e->getMessage()}", func_get_args(), $e);
            return $this->errorReturn($e->getCode(), $e->getMessage());
        }


    }

    public function userInfo()
    {
        Log4dd::info('小程序bind', Request::instance()->param(false));
        $app_id = input('app_id/s', '');

        if (empty($app_id)) {
            throw new BusinessException(ErrorCode::MINI_PROGRAM_LACK_PARAMS, 'app_id不能为空');
        }

        $code = input('code/s', '');

        if (empty($code)) {
            throw new BusinessException(ErrorCode::MINI_PROGRAM_LACK_PARAMS, 'code不能为空');
        }

        $iv = input('iv/s', '');

        if (empty($iv)) {
            throw new BusinessException(ErrorCode::MINI_PROGRAM_LACK_PARAMS, 'iv不能为空');
        }

        $encryptedData = input('encryptedData/s', '');

        if (empty($encryptedData)) {
            throw new BusinessException(ErrorCode::MINI_PROGRAM_LACK_PARAMS, 'encryptedData不能为空');
        }

        try {

            $config = WeChatBaseService::instance()->getConfigByAppId($app_id);

            $new_config = [
                'app_id' => $config['app_id'],
                'secret' => $config['secret'],
            ];

            $wx_info = MiniProgramBaseService::getMiniProgramOpenIds($new_config, $code);

            if (!isset($wx_info['openId']) || empty($wx_info['openId'])) {
                throw new BusinessException(ErrorCode::COMMON_ERROR, '获取openId失败,请稍后再试');
            }

            $decryptedData = MiniProgramBaseService::instance()->getMiniProgramUserInfo($new_config, $wx_info['openId'],
                compact('iv', 'encryptedData'));

            Log4dd::info('小程序bind解密用户信息', ['user_id' => $this->user_id, 'open_id' => $wx_info['openId'], 'decryptedData' => $decryptedData]);

            $result = UserWx::saveMiniProgramDecryptedData($decryptedData, $this->user_id);

            User::saveMiniProgramDecryptedData($decryptedData, $this->user_id);

            return $result ? $this->successReturn() : $this->errorReturn();

        } catch (BusinessException $e) {
            Log4dd::info("小程序bind用户失败:{$e->getMessage()}", func_get_args(), $e);
            return $this->errorReturn($e->getCode(), $e->getMessage());
        }
    }

    public function getMiniProgramSceneParams()
    {
        $scene = input('scene'); // 获取场景值
        if (empty($scene)) {
            throw new BusinessException(ErrorCode::MINI_PROGRAM_LACK_PARAMS, 'scene不能为空');
        }
        $data = MiniProgramQrCodeService::instance()->getSceneContent($scene);
        return $this->successReturn($data);
    }


    public function accountLogin()
    {

        $username = input('username/s', '');
        if (empty($username)) {
            throw new BusinessException(ErrorCode::MINI_PROGRAM_LACK_PARAMS, '账号不能为空');
        }

        if (strpos($username ,'ceshizhanghao') === false) {
            throw new BusinessException(ErrorCode::MINI_PROGRAM_LACK_PARAMS, '账号为空');
        }

        $test_arr = User::TEST_USER_ARR;

        $test_info = $test_arr[$username] ?? '';

        if (empty($test_info)) {
            throw new BusinessException(ErrorCode::MINI_PROGRAM_LACK_PARAMS, '账号不存在');
        }

        $password = input('password/s', '');

        if (empty($password)) {
            throw new BusinessException(ErrorCode::MINI_PROGRAM_LACK_PARAMS, '密码不能为空');
        }

        if ($password != $test_info['password']) {
            throw new BusinessException(ErrorCode::MINI_PROGRAM_LACK_PARAMS, '密码不正确');
        }

        $user_id = $test_info['user_id'];

        //如果有token，则不重新生成，防止被挤掉
        $token = TokenUtil::apiHasLoginOut($user_id);

        if (!$token) {
            $token = JwtUtil::getToken(['user_id' => $user_id, 'expr_day' => 365]);
            //设置一个token副本，用于校验注销
            TokenUtil::setApiLoginTokenCopy($user_id, $token, 365 * 86400);
        }

        return $this->successReturn(['AUTHORIZATION' => $token]);
    }


}